﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace JeuDeDames_v1._02
{
    public class MultithreadingIA
    {
        #region Attributs
        private Damier damierDeBase;

        private List<Damier> lesDamiers;

        private List<Thread> lesThreads;
        #endregion

        #region Constructeur
        public MultithreadingIA(Damier d)
        {
            damierDeBase = d;
            lesDamiers = new List<Damier>();
            lesThreads = new List<Thread>();
            setDamiers(d);
            affecterListesCoups();
            setThreads();
        }
        #endregion

        #region Méthodes
        public List<Damier> getDamiers()
        {
            return lesDamiers;
        }

        public List<Thread> getThreads()
        {
            return lesThreads;
        }

        public void setThreads()
        {
            int i = 0;
            foreach(Damier d in lesDamiers)
            {
                Joueur iA = d.jcourant();
                Thread thread = new Thread(new ParameterizedThreadStart(((Ordinateur)iA).alphaBetaPremier));
                thread.Priority = ThreadPriority.Highest;
                lesThreads.Add(thread);
                i++;
            }
        }

        public Coup lancerThreads()
        {
            Coup meilleurCoup = new Coup();
            meilleurCoup.evaluation = int.MinValue;
            List<Coup> lesMeilleursCoups = new List<Coup>();
            Coup unCoup;
            for (int i = 0; i < lesThreads.Count; i++)
            {
                lesThreads[i].Start(lesDamiers[i]);
            }
            bool threadTerminer = false;
            while (threadTerminer == false)
            {
                threadTerminer = isThreadEnCours();
            }
            foreach (Damier d in lesDamiers)
            {
                unCoup = (d.jcourant() as Ordinateur).getMeilleurCoup();
                unCoup.ToString();
                if (unCoup.evaluation > meilleurCoup.evaluation)
                {
                    lesMeilleursCoups.Clear();
                    meilleurCoup = unCoup;
                    lesMeilleursCoups.Add(meilleurCoup);
                }
                else if (unCoup.evaluation == meilleurCoup.evaluation)
                {
                    lesMeilleursCoups.Add(unCoup);
                }
            }
            
            Random r = new Random();
            meilleurCoup = lesMeilleursCoups[r.Next(lesMeilleursCoups.Count())];

            return meilleurCoup;
        }

        private bool isThreadEnCours()
        {
            foreach(Thread unThread in lesThreads)
            {
                unThread.Join(); 
            }

            return true;
        }

        public void setDamiers(Damier d)
        {
            Damier.enregistrer(d, "copieDamier.bin");
            damierDeBase = d;
            for (int i = 0; i < nombreProcesseursUtilises(d); i++)
            {
                lesDamiers.Add(dupliquerDamier(d));
            }

        }

        private int nombreProcesseursUtilises(Damier d)
        {
            Joueur courant=d.jcourant();
            int nbProcesseur = (System.Environment.ProcessorCount)*2;
            if (nbProcesseur > courant.coupsPossibles.Count)    //Si le joueur a moins de coups possible qu'il y a de processeur.
            {
                return courant.coupsPossibles.Count;
            }
            return nbProcesseur;
        }

        /**
         * affecterListeCoups change les coups possibles du joueur courant.
         * Ainsi tous les damiers présents dans lesDamiers possèderont une liste de coups différentes des autres.
         */
        private void affecterListesCoups()
        {
            int nbListes = nombreProcesseursUtilises(damierDeBase);
            for (int i = 0; i < nbListes; i++)
            {
                /*pour chaque damier, la liste des coups possible du joueur courant est maj.*/
                lesDamiers[i].jcourant().coupsPossibles = decouperListeCoups(i + 1); 
                
            }
        }

        /**
         * decouperListeCoups() renvoit une partie de la liste des coupsPossibles du joueur courant.
         */
        private List<Coup> decouperListeCoups(int numeroDeCoupe)
        {
            Joueur j = lesDamiers[numeroDeCoupe-1].jcourant();
            int nombreDecoupes = nombreProcesseursUtilises(lesDamiers[numeroDeCoupe-1]);
            int nbCoupsPossibles = j.coupsPossibles.Count;  //nombre de coup du joueur courant.
            int nbCoupsParListes = nbCoupsPossibles / nombreDecoupes; //nombre d'élement qu'il y a dans la futur liste.
            int debListe = nbCoupsParListes * (numeroDeCoupe-1) ;

            List<Coup> listeDecouper = new List<Coup>();

            for (int i = debListe; i < nbCoupsParListes + debListe; i++)
            {
                listeDecouper.Add(j.coupsPossibles[i]);
            }

            return listeDecouper;
        }

        #region Autres
        public Damier dupliquerDamier(Damier d)
        {
            Damier unDamier = Damier.charger<Damier>("copieDamier.bin");

            return unDamier;
        }
        #endregion

        #endregion
    }
}
